package graph_viewer.structure.builder;

import java.awt.*;
import java.io.*;
import java.util.*;

import graph_viewer.app_exception.*;

import graph_viewer.factory.*;
import graph_viewer.structure.*;
import graph_viewer.util.*;


/**
	This class read the .ts data file from Kevin Pulo, which is created by the tools of  Tom Soyer
*/
public class TomS_Graph_Builder extends Basic_Builder{	
	private File	node_data;

	//============================================================================
	// main() for test
	//============================================================================	
	public static void main(String arg[])  throws IOException{
	}	


	//============================================================================
	// constructor
	//============================================================================	
	public TomS_Graph_Builder( String a_file_name ) throws IOException{
		this( new File(a_file_name) );		
	}

	public TomS_Graph_Builder( File a_file ) throws IOException{
		if ( is_valid_data_file(a_file) ){
			set_file( a_file );
			Debug.println( " File is setted " + a_file, 2);
		} else {
			Debug.println( " File is null " , 2);
			node_data	= null;
		}
	}

	//============================================================================
	// setter&getter
	//============================================================================
	public void set_file( File a_file ){
		node_data	= a_file;
	}

	public File get_file(){
		return this.node_data;
	}
	
	//============================================================================
	// public methods
	//============================================================================
	public Graph build_clustered_graph( Tree cluster_tree ) throws IOException {
		return null;
	}
	
	
	//the first element of collection must be the node
	public Tree build_tree( Tree created_tree ) throws IOException{
		ArrayList 
			nodes_list	=	read_nodes_list(),
			edges_list	=	read_edges_list();

		ArrayList nodes = new ArrayList();

		for ( Iterator _i = edges_list.iterator(); _i.hasNext(); ){
			String[] edge_ends	= (String[])_i.next();

			//Debug.println( "\t" + edge_ends[0] + "--"+ edge_ends[1], 2 );
			
			Node 
				start_node	= search_node_by_label( nodes_list, edge_ends[0] ),
				end_node	= search_node_by_label( nodes_list, edge_ends[1] );
			
			start_node.add_child( end_node );
			end_node.set_parent( start_node );	
			
			if ( !nodes.contains( start_node ) ){
				nodes.add( start_node );
			}

			if ( !nodes.contains( end_node ) ){
				nodes.add( end_node );
			}
			
		}
		
		Node root	= search_root( nodes );

		created_tree	= new Generic_Tree( root );
		
		created_tree.set_tree( nodes );		

		return created_tree;
	}

	public ArrayList build_edges( Graph a_graph ) throws IOException{
		return read_edges_list();
	}

	//============================================================================
	// private methods
	//============================================================================
	protected String[] retrive_edge_information( String cross_vertice_pair, int start_index ){
		ArrayList edge_info = new ArrayList();
		StringTokenizer st	= new StringTokenizer( cross_vertice_pair );
		while ( st.hasMoreTokens() ){
			String s	= st.nextToken();
			//Debug.println( "parse edge info " + s, 2 );
			edge_info.add( s );
		}
		
		String 
			start_node	= (String)edge_info.get( start_index ),
			end_node	= (String)edge_info.get( start_index  + 1 );

		return new String[]{ start_node, end_node };
	}

	// @param nodes_list all nodes but one has parent. The node without parent is the root
	private Node search_root( ArrayList nodes_list ){
		ArrayList root_candidates	= new ArrayList();

		for ( Iterator _i = nodes_list.iterator(); _i.hasNext(); ){
			Node n	= (Node)_i.next();

			if ( n.get_parent() == null ){
				root_candidates.add( n );
			}
		}
		
		if ( root_candidates.size() != 1 ){
			throw new App_Exception( "No roots in a give node list." );
		}

		return (Node)root_candidates.get( 0 );		
	}
	
	private Node search_node_by_label( ArrayList nodes_list, String node_label ){		
		for ( Iterator _i = nodes_list.iterator(); _i.hasNext(); ){

			Node _n	= ( Node )_i.next();

			if ( _n.get_label().equals( node_label ) ){
				return _n;
			}
		}

		throw new App_Exception( "No node found!" );
	}
	// @ return an element of ArrayList is a node
	private ArrayList read_nodes_list() throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		nodes_list			= new ArrayList();
		
		int node_index	 = 0;
		while ( true ){
			String node_list_string = node_data_reader.readLine();
			
			if ( node_list_string == null ){
				break; //break at the end of the file
			}
			
			String node_list	= node_list_string.trim();

			if ( node_list.length() != 0 ){
				Node a_node	= new Node();
				
				a_node.set_label( "" + node_index );

				String[] b_t	 = File_Util.parse_ts_input( node_list );
				Debug.println( " bt:" + b_t[0], 2 );
				a_node.set_brief_text( b_t[0] );

				Debug.println( " F_t:" + b_t[1], 2 );
				a_node.set_text( b_t[1] );
	
				nodes_list.add( a_node );
				
				node_index++; 
			}else{ 
				break;//break when meet first blank line
			}
		}

		node_data_reader.close();

		return nodes_list;
	}
	
		// @ return an element of ArrayList is a node
	private ArrayList read_edges_list() throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		edges_list			= new ArrayList();
		
		boolean is_meet_first_blank	= false;
		while ( true ){
			String edge_list_string = node_data_reader.readLine();
			
			if ( edge_list_string == null ){
				break;
			}

			String edge_list	= edge_list_string.trim() ;
			
			//Debug.println( edge_list_string, 2 );
			if ( !is_meet_first_blank ){
				if ( edge_list_string.length() == 0 ){
					is_meet_first_blank = true;
				}
			}else{
				if ( edge_list_string.length() != 0 ){
					String[] edge_pair	= retrive_edge_information( edge_list_string, 0 );
					
					//Debug.println( edge_list_string, 2 );
					edges_list.add( edge_pair );
				}
			}			
		}
		
		node_data_reader.close();

		return edges_list;
	}
	
	
};
